#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSettings>
#include <QFileDialog>
#include <QLabel>
#include <QMessageBox>
#include <QLineEdit>
#include <QPushButton>
#include <QDesktopServices>
#ifdef QT_PRINTSUPPORT
#include <QPrinter>
#include <QPrintDialog>
#include <QPainter>
#endif
#include "AvatarLibrary.h"
#include "Program.h"
#include "entity/EntityLight.h"
#include "entity/EntityCamera.h"
#include "utility/ProjectReader.h"
#include "utility/ProjectWriter.h"
#include "dialog/dialog_publish.h"
#include "dialog/dialog_setup_scene.h"
#include "dialog/dialog_setup_plugin.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    QSettings settings;
    ui->setupUi(this);
    loadTheme(settings.value("theme", "light").toString());
    // 相机类型切换
    _toolbarCameraType = new QComboBox();
    _toolbarCameraType->setMinimumWidth(80);
    _toolbarCameraType->addItem("DEFAULT", "default");
    _toolbarCameraType->addItem("SMOOTH", "smooth");
    _toolbarCameraType->addItem("FREE", "free");
    _toolbarCameraType->addItem("GAZE", "gaze");
    _toolbarCameraType->addItem("VIEWER", "viewer");
    _toolbarCameraType->addItem("GEO", "geographic");
    _toolbarCameraType->setCurrentIndex(1);
    ui->toolBar->addWidget(_toolbarCameraType);
    // 命令输入框
    _statusbarLineEditCommand = new QLineEdit(this);
    _statusbarLineEditCommand->setAttribute(Qt::WA_InputMethodEnabled, false);
    _statusbarLineEditCommand->hide();
    _statusbarLineEditCommand->installEventFilter(this);
    _statusbarLabelCommand= new QLabel(this);
    _statusbarLabelCommand->setText("<a style='color:#0fb03c' href='#'>输入命令</a>");
    statusBar()->addPermanentWidget(_statusbarLineEditCommand);
    statusBar()->addPermanentWidget(_statusbarLabelCommand);
    // 界面设置
    resizeDocks({ui->dockWidget1, ui->dockWidget2, ui->dockWidget3}, {1, 1, 1}, Qt::Vertical);
    ui->stackedWidgetAttribute->setCurrentIndex(ui->stackedWidgetAttribute->count() - 1);
    _defaultWindowState = saveState();
    _savedViewStatus.fill(true, 4);
    ui->splitter->setSizes({10000, 0});
    // 处理相关信号
    setupSignal();
    // 检查系统 media 文件夹路径
    const QString appPath = QApplication::applicationDirPath() + QDir::separator();
    const QString parentPath = QString("..") + QDir::separator();
    Program::MediaDirectory = QDir::cleanPath(appPath + "media");
    if (!QDir(Program::MediaDirectory).exists()) Program::MediaDirectory = QDir::cleanPath(appPath + parentPath + "media");
    if (!QDir(Program::MediaDirectory).exists()) Program::MediaDirectory = QDir::cleanPath(appPath + parentPath + parentPath + "media");
    if (!QDir(Program::MediaDirectory).exists()) Program::MediaDirectory = QDir::cleanPath(appPath + parentPath + parentPath + parentPath + "media");
    if (!QDir(Program::MediaDirectory).exists()) statusBar()->showMessage(tr("错误"));
    else statusBar()->showMessage(tr("就绪"));
    startScene(Program::MediaDirectory);
}

MainWindow::~MainWindow()
{
    delete ui;
}

/**
 * @brief 获取渲染画面大小
 * @return
 */
QSize MainWindow::GetViewSize()
{
    return ui->widgetAvatarView->ScreenSize();
}

/**
 * @brief 打开项目工作区
 * @param workspace
 */
void MainWindow::OpenWorkspace(const QString &workspace)
{
    if (ProjectReader().Read(workspace))
    {
        Program::SetupProject();
        setWindowState(Qt::WindowMaximized);
    }
    else QMessageBox::warning(this, "错误", "打开项目失败");
}

/**
 * @brief 启动场景
 * @param path 场景目录
 */
void MainWindow::startScene(const QString& path)
{
    ui->widgetAvatarView->Start(path);
    ui->widgetSceneTree->Initialize();
    ui->widgetScriptEditor->Initialize();
    AvatarLibrary::avatar_log(1, [=](const QString& header, const QString& content) {
        emit sig_logMessage(header, content);
    });
}

/**
 * @brief 设置显示项目信息
 * @param path
 */
void MainWindow::showProject(const QString& path)
{
    this->setWindowTitle("AVATAR 编辑器 - " + path);
    _toolbarCameraType->blockSignals(true);
    if (Program::CameraParam.Type == EntityCamera::CameraType::DEFAULT) _toolbarCameraType->setCurrentIndex(0);
    else if (Program::CameraParam.Type == EntityCamera::CameraType::SMOOTH) _toolbarCameraType->setCurrentIndex(1);
    else if (Program::CameraParam.Type == EntityCamera::CameraType::FREE) _toolbarCameraType->setCurrentIndex(2);
    else if (Program::CameraParam.Type == EntityCamera::CameraType::GAZE) _toolbarCameraType->setCurrentIndex(3);
    else if (Program::CameraParam.Type == EntityCamera::CameraType::VIEWER) _toolbarCameraType->setCurrentIndex(4);
    else if (Program::CameraParam.Type == EntityCamera::CameraType::GEOGRAPHIC) _toolbarCameraType->setCurrentIndex(5);
    _toolbarCameraType->blockSignals(false);
    ui->widgetScriptTree->LoadScript();
    _commandHistory.clear();
}

/**
 * @brief 设置场景节点
 */
void MainWindow::setSceneTree()
{
    ui->widgetSceneTree->Reload();
}

/**
 * @brief 加载主题
 * @param name
 */
void MainWindow::loadTheme(const QString &name)
{
    QFile qssFile(":/resource/qss/" + name + ".qss");
    if(qssFile.open(QFile::ReadOnly))
    {
        setStyleSheet(QLatin1String(qssFile.readAll()));
        qssFile.close();
        if (Program::WorkingSpace.isEmpty())
        {
            Program::Config.Background = name == "dark" ? Vector3(0.16f, 0.16f, 0.16f) : Vector3(0.86f, 0.86f, 0.86f);
            AvatarLibrary::avatar_command(QString("graphics.background(%1,1.0)").arg(Program::Config.Background.ToString()));
        }
    }
}

/**
 * @brief 连接信号槽
 */
void MainWindow::setupSignal()
{
    connect(_toolbarCameraType, &QComboBox::currentIndexChanged, _toolbarCameraType, [=](int index) {
        QString type = _toolbarCameraType->currentData().toString();
        Vector3 pos(0.0f, 0.0f, 0.0f);
        AvatarLibrary::avatar_camera_position(pos);
        QString format = "camera.type('%1')\ncamera.position(%2)";
        AvatarLibrary::avatar_command(QString(format).arg(type, pos.ToString()));
        if (type == "default") Program::CameraParam.Type = EntityCamera::CameraType::DEFAULT;
        else if (type == "smooth") Program::CameraParam.Type = EntityCamera::CameraType::SMOOTH;
        else if (type == "free") Program::CameraParam.Type = EntityCamera::CameraType::FREE;
        else if (type == "gaze") Program::CameraParam.Type = EntityCamera::CameraType::GAZE;
        else if (type == "viewer") Program::CameraParam.Type = EntityCamera::CameraType::VIEWER;
        else if (type == "geographic") Program::CameraParam.Type = EntityCamera::CameraType::GEOGRAPHIC;
    });
    connect(_statusbarLineEditCommand, &QLineEdit::returnPressed, this, [=]() {
        QString text = _statusbarLineEditCommand->text().trimmed();
        _commandHistory.removeAll(text);
        _commandHistory.push_back(text);
        _commandHistoryIndex = _commandHistory.size();
        if (_commandHistory.size() > 20) _commandHistory.pop_front();
        if (text.startsWith("engine.log")) AvatarLibrary::avatar_command(text);
        else AvatarLibrary::avatar_command("engine.log(" + text + ")");
        _statusbarLineEditCommand->setText("");
    });
    connect(ui->widgetScriptTree, &WidgetScriptTree::sig_scriptSelected, ui->widgetScriptEditor, &WidgetScriptEditor::loadScript);
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_createNode, this, [=](const QString& type, EntitySceneNode* parent) {
        ui->stackedWidgetAttribute->setCurrentIndex(0);
        ui->widgetEditNode->newNode(type, parent);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_selectNode, this, [=](const QString& name) {
        statusBar()->showMessage(QString("%1").arg(name));
        const int idx = ui->stackedWidgetAttribute->currentIndex();
        if (idx == 1) ui->widgetNodeTransform->setupNode(name);
        else if (idx == 2) ui->widgetNodeMaterial->setupNode(name);
        else if (idx == 3) ui->widgetNodePhysical->setupNode(name);
        else ui->widgetEditNode->editNode(name);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_editNode, this, [=](const QString& name) {
        ui->stackedWidgetAttribute->setCurrentIndex(0);
        ui->widgetEditNode->editNode(name);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_nodeTransform, this, [=](const QString& name) {
        ui->stackedWidgetAttribute->setCurrentIndex(1);
        ui->widgetNodeTransform->setupNode(name);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_nodeMaterial, this, [=](const QString& name) {
        ui->stackedWidgetAttribute->setCurrentIndex(2);
        ui->widgetNodeMaterial->setupNode(name);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_nodePhysical, this, [=](const QString& name) {
        ui->stackedWidgetAttribute->setCurrentIndex(3);
        ui->widgetNodePhysical->setupNode(name);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_nodeAttachment, this, [=](const QString& name) {
        ui->stackedWidgetAttribute->setCurrentIndex(4);
        ui->widgetNodeAttachment->setupNode(name);
    });
    connect(ui->widgetSceneTree, &WidgetSceneTree::sig_nodeAnimation, this, [=](const QString& name) {
        ui->stackedWidgetAttribute->setCurrentIndex(5);
        ui->widgetNodeAnimation->setupNode(name);
    });
    connect(ui->widgetScriptEditor, &WidgetScriptEditor::sig_createGui, this, [=]() {
        ui->stackedWidgetAttribute->setCurrentIndex(6);
        ui->widgetEditGui->newGui();
    });
    connect(ui->widgetEditNode, &WidgetEditNode::sig_editApply, ui->widgetSceneTree, &WidgetSceneTree::EditNode);
    connect(ui->widgetEditGui, &WidgetEditGui::sig_editApply, ui->widgetScriptEditor, &WidgetScriptEditor::EditGui);
    connect(this, &MainWindow::sig_saveProject, ui->widgetScriptEditor, &WidgetScriptEditor::saveModify);
    connect(this, &MainWindow::sig_logMessage, ui->textEditLog, &WidgetLogText::showMessage);
    connect(_statusbarLabelCommand, &QLabel::linkActivated, this, [=]() {
        if (_statusbarLineEditCommand->isHidden())
        {
            _statusbarLineEditCommand->show();
            _statusbarLineEditCommand->setFocus();
        }
        else _statusbarLineEditCommand->hide();
    });
}

/**
 * @brief 事件过滤器
 * @param obj
 * @param event
 * @return
 */
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (_statusbarLineEditCommand == obj && event->type() == QEvent::KeyPress)
    {
        // 按上下键切换最近输入命令
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)
        {
            _commandHistoryIndex += keyEvent->key() == Qt::Key_Up ? -1 : 1;
            _commandHistoryIndex = qMin(qMax(_commandHistoryIndex, 0), _commandHistory.size() - 1);
            if (_commandHistoryIndex >= 0) _statusbarLineEditCommand->setText(_commandHistory.at(_commandHistoryIndex));
            return true;
        }
    }
    return QObject::eventFilter(obj, event);
}

/**
 * @brief 场景/脚本切换界面
 * @param index
 */
void MainWindow::on_tabWidget_currentChanged(int index)
{
    if (index == 0)
    {
        _savedSplitterStatus = ui->splitter->saveState();
        ui->splitter->setSizes({10000, 0});
    }
    else
    {
        ui->splitter->restoreState(_savedSplitterStatus);
        if (ui->splitter->sizes()[1] == 0) ui->splitter->setSizes({5000, 5000});
    }
    ui->stackedWidgetAttribute->setCurrentIndex(ui->stackedWidgetAttribute->count() - 1);
}

/**
 * @brief 新建项目
 */
void MainWindow::on_actionNew_triggered()
{
    QSettings settings;
    QString fileName = QFileDialog::getSaveFileName(this,
        "新建项目",
        settings.value("project/path", QCoreApplication::applicationDirPath()).toString(),
        "AVATAR项目 (*.avatarproj)");
    if (fileName.isEmpty()) return;
    QFileInfo fileInfo(fileName);
    settings.setValue("project/path", fileInfo.absolutePath());
    if (fileInfo.suffix().toUpper() != "AVATARPROJ") fileName += ".avatarproj";
    Program::Config.Init();
    Program::LightParam = EntityLight();
    Program::CameraParam = EntityCamera();
    Program::SceneNodeList.clear();
    Program::UserScript.clear();
    ProjectWriter().Write(fileName);
    Program::SetupProject();
}

/**
 * @brief 打开项目
 */
void MainWindow::on_actionOpen_triggered()
{
    QSettings settings;
    QString fileName = QFileDialog::getOpenFileName(this,
        "打开项目",
        settings.value("project/path", QCoreApplication::applicationDirPath()).toString(),
        "AVATAR项目 (*.avatarproj)",
        nullptr,
        QFileDialog::DontUseNativeDialog);
    if (fileName.isEmpty()) return;
    settings.setValue("project/path", QFileInfo(fileName).absolutePath());
    if (ProjectReader().Read(fileName)) Program::SetupProject();
    else QMessageBox::warning(this, "错误", "打开项目失败");
}

/**
 * @brief 保存项目
 */
void MainWindow::on_actionSave_triggered()
{
    emit sig_saveProject();
    Program::CameraParam.Update();
    if (Program::WorkingSpace.isEmpty())
    {
        QSettings settings;
        QString fileName = QFileDialog::getSaveFileName(this,
            "保存项目",
            settings.value("project/path", QCoreApplication::applicationDirPath()).toString(),
            "AVATAR项目 (*.avatarproj)");
        if (fileName.isEmpty()) return;
        settings.setValue("project/path", QFileInfo(fileName).absolutePath());
        ProjectWriter().Write(fileName);
        Program::SetupProject();
    } else ProjectWriter().Write(Program::WorkingSpace);
}

/**
 * @brief 打印
 */
void MainWindow::on_actionPrint_triggered()
{
#ifdef QT_PRINTSUPPORT
    QPrinter printer(QPrinter::HighResolution);
    printer.setPageMargins(QMargins(15, 20, 15, 20));
    printer.setPageSize(QPageSize::A4);
    printer.setPageOrientation(QPageLayout::Landscape);
    QPrintDialog dlg(&printer, this);
    dlg.setWindowTitle(tr("打印渲染图"));
    if (dlg.exec() == QDialog::Accepted)
    {
        QString imagefile = QDir(QDir::tempPath()).absoluteFilePath("capture.png");
        AvatarLibrary::avatar_command("graphics.screenshot('" + imagefile + "')");
        AvatarLibrary::avatar_update();
        QImage image(imagefile);
        QPainter painter(&printer);
        painter.drawImage(0, 0, image.scaled(painter.viewport().size(), Qt::KeepAspectRatio));
    }
#else
    statusBar()->showMessage(tr("不支持打印"));
#endif
}

/**
 * @brief 发布项目
 */
void MainWindow::on_actionPublish_triggered()
{
    if (!Program::WorkingSpace.isEmpty())
    {
        DialogPublish* dlg = new DialogPublish(this);
        dlg->setAttribute(Qt::WA_DeleteOnClose);
        dlg->exec();
    }
    else QMessageBox::warning(this, "提示", "当前无项目");
}

/**
 * @brief 退出程序
 */
void MainWindow::on_actionExit_triggered()
{
    QApplication::closeAllWindows();
}

/**
 * @brief 全屏视图
 */
void MainWindow::on_actionViewFull_triggered()
{
    // 判断是否普通状态
    if (_savedViewStatus.at(0))
    {
        _savedViewStatus.setBit(0, false);
        _savedViewStatus.setBit(1, ui->dockWidget1->isVisible());
        _savedViewStatus.setBit(2, ui->dockWidget2->isVisible());
        _savedViewStatus.setBit(3, ui->dockWidget3->isVisible());
        ui->dockWidget1->hide();
        ui->dockWidget2->hide();
        ui->dockWidget3->hide();
    }
    else
    {
        _savedViewStatus.setBit(0, true);
        ui->dockWidget1->setVisible(_savedViewStatus.at(1));
        ui->dockWidget2->setVisible(_savedViewStatus.at(2));
        ui->dockWidget3->setVisible(_savedViewStatus.at(3));
    }
}

/**
 * @brief 重置视图
 */
void MainWindow::on_actionViewReset_triggered()
{
    restoreState(_defaultWindowState);
    _savedViewStatus.fill(true, 4);
}

/**
 * @brief 浅色主题
 */
void MainWindow::on_actionThemeLight_triggered()
{
    QSettings settings;
    settings.setValue("theme", "light");
    loadTheme("light");
}

/**
 * @brief 深色主题
 */
void MainWindow::on_actionThemeDark_triggered()
{
    QSettings settings;
    settings.setValue("theme", "dark");
    loadTheme("dark");
}

/**
 * @brief 场景设置
 */
void MainWindow::on_actionSetupScene_triggered()
{
    DialogSetupScene* dlg = new DialogSetupScene(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->show();
}

/**
 * @brief 插件设置
 */
void MainWindow::on_actionSetupPlugin_triggered()
{
    DialogSetupPlugin* dlg = new DialogSetupPlugin(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->show();
}

/**
 * @brief 打开帮助文档
 */
void MainWindow::on_actionHelpChm_triggered()
{

}

/**
 * @brief 打开个人主页
 */
void MainWindow::on_actionHelpHome_triggered()
{
    QDesktopServices::openUrl(QUrl("https://blog.csdn.net/luoyexunxue", QUrl::TolerantMode));
}
